/*
 *	               _ooOoo_ 
 *	              o8888888o 
 *	              88" . "88 
 *	              (| -_- |) 
 *	              O\  =  /O 
 *	           ____/`---'\____ 
 *	         .'  \\|     |//  `. 
 *	        /  \\|||  :  |||//  \ 
 *	       /  _||||| -:- |||||-  \ 
 *	       |   | \\\  -  /// |   | 
 * 	       | \_|  ''\---/''  |   | 
 * 	       \  .-\__  `-`  ___/-. / 
 * 	    ___ `. .'  /--.--\  `. . __ 
 *	  ."" '<  `.___\_<|>_/___.'  >'"". 
 *	 | | :  `- \`.;`\ _ /`;.`/ - ` : | | 
 *	 \  \ `-.   \_ __\ /__ _/   .-` /  / 
 *======`-.____`-.___\_____/___.-`____.-'====== 
 *                   `=---=' 
 *^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
 *佛祖保佑       永无BUG 
 * File name:         ImageUtil.java
 * Copyright@blog.ilvelh.com(China)
 * Editor:           JDK1.7_40
 */
package com.ilvelh.tools;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;

/**
 * 图像处理类,可缩放,剪裁等操作
 * <p>
 * Author: ilvelh
 * <p>
 * Date:2014-9-9 Time:下午12:14:52
 * <p>
 */
public class ImageUtil {
	private BufferedImage bufferedImage;
	private String fileName;
	private int imageType = 1;

	/**
	 * 判断流文件是否为图片
	 * 
	 * @param is
	 * @return
	 */
	public static boolean isImage(InputStream is) {
		Iterator<ImageReader> iter = ImageIO.getImageReaders(is);
		if (!iter.hasNext()) {
			// 文件不是图片
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 判断流文件是否为图片
	 * 
	 * @param is
	 * @return
	 * @throws IOException 
	 */
	public static boolean isImage1(InputStream is) throws IOException {
		BufferedImage bi = ImageIO.read(is);
		if (bi == null) {
			// 文件不是图片
			return false;
		} else {
			// ImageIO.write(bi, Constant.JPG, fos);
			return true;
		}
	}

	public ImageUtil(BufferedImage bufferedImage) {
		super();
		this.bufferedImage = bufferedImage;
	}

	public BufferedImage getBufferedImage() {
		return bufferedImage;
	}

	public void setBufferedImage(BufferedImage bufferedImage) {
		this.bufferedImage = bufferedImage;
	}

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public ImageUtil(File imageFile) {
		try {
			this.bufferedImage = ImageIO.read(imageFile);
			this.fileName = imageFile.getAbsolutePath();
		} catch (Exception e) {
			e.printStackTrace();
			this.bufferedImage = null;
			imageFile = null;
		}
	}

	public ImageUtil(String imageFilePath) {
		this(new File(imageFilePath));
	}

	public BufferedImage getAsBufferedImage() {
		return this.bufferedImage;
	}

	public void saveAs(String fileName) {
		saveImage(new File(fileName));
		this.fileName = fileName;
	}

	public void save() {
		saveImage(new File(this.fileName));
	}

	/**
	 * 设置新图片的size
	 * 
	 * @param percentOfOriginal
	 *            百分比
	 */
	public void resize(int percentOfOriginal) {
		int newWidth = this.bufferedImage.getWidth() * percentOfOriginal / 100;
		int newHeight = this.bufferedImage.getHeight() * percentOfOriginal
				/ 100;
		resize(newWidth, newHeight);
	}

	/**
	 * 设置新图片的size
	 * 
	 * @param percentOfOriginal
	 *            百分比
	 */
	public void resize(double percentOfOriginal) {
		int newWidth = (int) (this.bufferedImage.getWidth() * percentOfOriginal / 100);
		int newHeight = (int) (this.bufferedImage.getHeight()
				* percentOfOriginal / 100);
		resize(newWidth, newHeight);
	}

	/**
	 * 设置新图片的size
	 * 
	 * @param newWidth
	 *            宽度
	 * @param newHeight
	 *            高度
	 */
	public void resize(int newWidth, int newHeight) {
		int oldWidth = this.bufferedImage.getWidth();
		int oldHeight = this.bufferedImage.getHeight();

		if ((newWidth == -1) || (newHeight == -1)) {
			if (newWidth == -1) {
				if (newHeight == -1) {
					return;
				}

				newWidth = newHeight * oldWidth / oldHeight;
			} else {
				newHeight = newWidth * oldHeight / oldWidth;
			}
		}

		BufferedImage result = new BufferedImage(newWidth, newHeight, imageType);

		int widthSkip = oldWidth / newWidth;
		int heightSkip = oldHeight / newHeight;

		if (widthSkip == 0)
			widthSkip = 1;
		if (heightSkip == 0)
			heightSkip = 1;

		for (int x = 0; x < oldWidth; x += widthSkip) {
			for (int y = 0; y < oldHeight; y += heightSkip) {
				int rgb = this.bufferedImage.getRGB(x, y);

				if ((x / widthSkip < newWidth) && (y / heightSkip < newHeight)) {
					result.setRGB(x / widthSkip, y / heightSkip, rgb);
				}
			}

		}

		this.bufferedImage = result;
	}

	/**
	 * 设置像素
	 * 
	 * @param numToAdd
	 */
	public void addPixelColor(int numToAdd) {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		for (int x = 0; x < width; ++x)
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				this.bufferedImage.setRGB(x, y, rgb + numToAdd);
			}
	}

	/**
	 * 转换为黑白图片
	 */
	public void convertToBlackAndWhite() {
		ColorSpace gray_space = ColorSpace.getInstance(1003);
		ColorConvertOp convert_to_gray_op = new ColorConvertOp(gray_space, null);
		convert_to_gray_op.filter(this.bufferedImage, this.bufferedImage);
	}

	/**
	 * 向左旋转
	 */
	public void rotateLeft() {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(height, width, imageType);

		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(y, x, rgb);
			}
		}

		this.bufferedImage = result;
	}

	/**
	 * 向右旋转
	 */
	public void rotateRight() {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(height, width, imageType);

		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(height - y - 1, x, rgb);
			}
		}

		this.bufferedImage = result;
	}

	/**
	 * 旋转180度
	 */
	public void rotate180() {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(width, height, imageType);

		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(width - x - 1, height - y - 1, rgb);
			}
		}

		this.bufferedImage = result;
	}

	public void flipHorizontally() {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(width, height, imageType);

		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(width - x - 1, y, rgb);
			}
		}

		this.bufferedImage = result;
	}

	public void flipVertically() {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(width, height, imageType);

		for (int x = 0; x < width; ++x) {
			for (int y = 0; y < height; ++y) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(x, height - y - 1, rgb);
			}
		}

		this.bufferedImage = result;
	}

	public void multiply(int timesToMultiplyVertically,
			int timesToMultiplyHorizantelly) {
		multiply(timesToMultiplyVertically, timesToMultiplyHorizantelly, 0);
	}

	public void multiply(int timesToMultiplyVertically,
			int timesToMultiplyHorizantelly, int colorToHenhancePerPixel) {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		BufferedImage result = new BufferedImage(width
				* timesToMultiplyVertically, height
				* timesToMultiplyHorizantelly, imageType);

		for (int xx = 0; xx < timesToMultiplyVertically; ++xx) {
			for (int yy = 0; yy < timesToMultiplyHorizantelly; ++yy) {
				for (int x = 0; x < width; ++x) {
					for (int y = 0; y < height; ++y) {
						int rgb = this.bufferedImage.getRGB(x, y);
						result.setRGB(width * xx + x, height * yy + y, rgb
								+ colorToHenhancePerPixel * (yy + xx));
					}
				}
			}

		}

		this.bufferedImage = result;
	}

	/**
	 * 添加logo
	 * 
	 * @param newImagePath
	 */
	public void combineWithPicture(String newImagePath) {
		combineWithPicture(newImagePath, 1);
	}

	/**
	 * 添加logo
	 * 
	 * @param newImagePath
	 * @param jump
	 */
	public void combineWithPicture(String newImagePath, int jump) {
		try {
			BufferedImage bufferedImage2 = ImageIO.read(new File(newImagePath));
			combineWithPicture(bufferedImage2, jump, null);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * 添加logo
	 * 
	 * @param image2
	 */
	public void combineWithPicture(ImageUtil image2) {
		combineWithPicture(image2.getAsBufferedImage(), 2, null);
	}

	/**
	 * 添加logo
	 * 
	 * @param image2
	 * @param jump
	 */
	public void combineWithPicture(ImageUtil image2, int jump) {
		combineWithPicture(image2.getAsBufferedImage(), jump, null);
	}

	/**
	 * 添加logo
	 * 
	 * @param image2
	 * @param ignoreColor
	 */
	public void combineWithPicture(ImageUtil image2, Color ignoreColor) {
		combineWithPicture(image2.getAsBufferedImage(), 2, ignoreColor);
	}

	/**
	 * 添加logo
	 * 
	 * @param image2
	 * @param jump
	 * @param ignoreColor
	 */
	public void combineWithPicture(ImageUtil image2, int jump, Color ignoreColor) {
		combineWithPicture(image2.getAsBufferedImage(), jump, ignoreColor);
	}

	/**
	 * 添加logo
	 * 
	 * @param bufferedImage2
	 * @param jump
	 * @param ignoreColor
	 */
	private void combineWithPicture(BufferedImage bufferedImage2, int jump,
			Color ignoreColor) {
		checkJump(jump);

		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		int width2 = bufferedImage2.getWidth();
		int height2 = bufferedImage2.getHeight();

		int ignoreColorRgb = -1;

		if (ignoreColor != null) {
			ignoreColorRgb = ignoreColor.getRGB();
		}

		for (int y = 0; y < height; ++y)
			for (int x = y % jump; x < width; x += jump) {
				if (x >= width2)
					continue;
				if (y >= height2) {
					continue;
				}

				int rgb = bufferedImage2.getRGB(x, y);
				if (rgb != ignoreColorRgb)
					this.bufferedImage.setRGB(x, y, rgb);
			}
	}

	/**
	 * 截图
	 * 
	 * @param startX
	 * @param startY
	 * @param endX
	 * @param endY
	 */
	public void crop(int startX, int startY, int endX, int endY) {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		if (startX == -1) {
			startX = 0;
		}

		if (startY == -1) {
			startY = 0;
		}

		if (endX == -1) {
			endX = width - 1;
		}

		if (endY == -1) {
			endY = height - 1;
		}

		if (startX > width) {
			startX = width - 1;
		}

		if (startY > height) {
			startY = height - 1;
		}

		if (endX > width) {
			endX = width - 1;
		}

		if (endY > height) {
			endY = height - 1;
		}

		BufferedImage result = new BufferedImage(endX - startX + 1, endY
				- startY + 1, imageType);

		for (int y = startY; y < endY; ++y) {
			for (int x = startX; x < endX; ++x) {
				int rgb = this.bufferedImage.getRGB(x, y);
				result.setRGB(x - startX, y - startY, rgb);
			}
		}
		this.bufferedImage = result;
	}

	/**
	 * 保存文件
	 * 
	 * @param file
	 */
	private void saveImage(File file) {
		try {
			ImageIO.write(this.bufferedImage, getFileType(file), file);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void emphasize(int startX, int startY, int endX, int endY) {
		emphasize(startX, startY, endX, endY, Color.BLACK, 3);
	}

	public void emphasize(int startX, int startY, int endX, int endY,
			Color backgroundColor) {
		emphasize(startX, startY, endX, endY, backgroundColor, 3);
	}

	public void emphasize(int startX, int startY, int endX, int endY, int jump) {
		emphasize(startX, startY, endX, endY, Color.BLACK, jump);
	}

	public void emphasize(int startX, int startY, int endX, int endY,
			Color backgroundColor, int jump) {
		checkJump(jump);

		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		if (startX == -1) {
			startX = 0;
		}

		if (startY == -1) {
			startY = 0;
		}

		if (endX == -1) {
			endX = width - 1;
		}

		if (endY == -1) {
			endY = height - 1;
		}

		for (int y = 0; y < height; ++y)
			for (int x = y % jump; x < width; x += jump) {
				if ((y >= startY) && (y <= endY) && (x >= startX)
						&& (x <= endX)) {
					continue;
				}

				this.bufferedImage.setRGB(x, y, backgroundColor.getRGB());
			}
	}

	private void checkJump(int jump) {
		if (jump < 1)
			throw new RuntimeException("Error: jump can not be less than 1");
	}

	public void addColorToImage(Color color, int jump) {
		addColorToImage(color.getRGB(), jump);
	}

	public void addColorToImage(int rgb, int jump) {
		checkJump(jump);

		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();

		for (int y = 0; y < height; ++y)
			for (int x = y % jump; x < width; x += jump)
				this.bufferedImage.setRGB(x, y, rgb);
	}

	public void affineTransform(double fShxFactor, double fShyFactor) {
		try {
			AffineTransform shearer = AffineTransform.getShearInstance(
					fShxFactor, fShyFactor);
			AffineTransformOp shear_op = new AffineTransformOp(shearer, null);
			this.bufferedImage = shear_op.filter(this.bufferedImage, null);
		} catch (Exception e) {
		}
	}

	private String getFileType(File file) {
		String fileName = file.getName();
		int idx = fileName.lastIndexOf(".");
		if (idx == -1) {
			throw new RuntimeException("Invalid file name");
		}

		return fileName.substring(idx + 1);
	}

	public int getWidth() {
		return this.bufferedImage.getWidth();
	}

	public int getHeight() {
		return this.bufferedImage.getHeight();
	}

	public void imageWater(String imagePath) {
		imageWater(imagePath, 0.5f, 0, 0);

	}

	public void imageWater(BufferedImage bi, float alpha, int startX, int startY) {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();
		int width2 = bi.getWidth();
		int height2 = bi.getHeight();

		BufferedImage img = new BufferedImage(width, height, imageType);
		Graphics2D g = img.createGraphics();

		g.drawImage(bufferedImage, 0, 0, width, height, null);
		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
				alpha));
		g.drawImage(bi, startX, startY, width2, height2, null);

		g.dispose();
		bufferedImage = img;
	}

	public void imageWater(File imageFile, float alpha, int startX, int startY) {
		try {
			InputStream is = new FileInputStream(imageFile);
			BufferedImage bi = ImageIO.read(is);
			imageWater(bi, alpha, startX, startY);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 添加水印
	 * 
	 * @param logoPath
	 * @param alpha
	 * @param startX
	 * @param startY
	 */
	public void imageWater(String imagePath, float alpha, int startX, int startY) {
		try {
			BufferedImage bi = ImageIO.read(new File(imagePath));
			imageWater(bi, alpha, startX, startY);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void textWater(String text) {
		Font font = new Font("黑体", Font.BOLD, 25);
		textWater(text, 1.0f, 0, 0, font, Color.RED);

	}

	/**
	 * 添加水印
	 * 
	 * @param text
	 * @param alpha
	 * @param startX
	 * @param startY
	 */
	public void textWater(String text, float alpha, int startX, int startY,
			Font font, Color color) {
		int width = this.bufferedImage.getWidth();
		int height = this.bufferedImage.getHeight();
		BufferedImage img = new BufferedImage(width, height, imageType);
		Graphics2D g = img.createGraphics();

		g.drawImage(bufferedImage, 0, 0, width, height, null);
		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
				alpha));

		g.setFont(font);
		g.setPaint(color);

		FontRenderContext context = g.getFontRenderContext();
		font.getStringBounds(text, context);

		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		FontMetrics fm = g.getFontMetrics();
		g.drawString(text, startX, startY + fm.getHeight());

		g.dispose();
		bufferedImage = img;
	}
}
